package com.shelpe.services.sinbad.controller;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shelpe.services.sinbad.controller.KeywordsController.PricingKeyword;
import com.shelpe.services.sinbad.dao.KeywordMapper;
import com.shelpe.services.sinbad.entity.jpa.Adgroup;
import com.shelpe.services.sinbad.entity.jpa.AdgroupLog;
import com.shelpe.services.sinbad.entity.jpa.Creative;
import com.shelpe.services.sinbad.entity.jpa.CreativeLog;
import com.shelpe.services.sinbad.entity.jpa.DriveType;
import com.shelpe.services.sinbad.entity.jpa.KeywordsLog;
import com.shelpe.services.sinbad.entity.jpa.OnlineStatus;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.entity.jpa.vo.AdgroupVo;
import com.shelpe.services.sinbad.entity.jpa.vo.ConvertKeywordNewVo;
import com.shelpe.services.sinbad.entity.jpa.vo.CreativeVo;
import com.shelpe.services.sinbad.entity.jpa.vo.DisplayKeywordNewVo;
import com.shelpe.services.sinbad.entity.jpa.vo.DisplayKeywordOldVo;
import com.shelpe.services.sinbad.entity.jpa.vo.DisplayKeywordVo;
import com.shelpe.services.sinbad.entity.jpa.vo.KeywordsVo;
import com.shelpe.services.sinbad.model.Keyword;
import com.shelpe.services.sinbad.model.KeywordExample;
import com.shelpe.services.sinbad.model.RptKeywordParam;
import com.shelpe.services.sinbad.repository.jpa.AdgroupLogRepository;
import com.shelpe.services.sinbad.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbad.repository.jpa.CreativeLogRepository;
import com.shelpe.services.sinbad.repository.jpa.CreativeRepository;
import com.shelpe.services.sinbad.repository.jpa.KeywordsLogRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;
import com.shelpe.services.sinbad.service.PlatformService;
import com.shelpe.services.sinbad.service.RptKeywordService;
import com.shelpe.services.sinbad.service.impl.OopKeywordService;
import com.shelpe.services.sinbad.service.simbaproxy.AdgroupClient;
import com.shelpe.services.sinbad.service.simbaproxy.AdgroupClient.CreateAdgroupResponse;
import com.shelpe.services.sinbad.service.simbaproxy.AdgroupClient.CreateCreativeResponse;
import com.shelpe.services.sinbad.service.simbaproxy.AdgroupClient.GetCreativeResponse;
import com.shelpe.services.sinbad.service.simbaproxy.SimbaProxyBaseDto;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("/sinbadservice")
@Slf4j
public class AdgroupController {

	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private CreativeRepository creativeRepository;
	@Autowired
	private AdgroupClient adgroupClient;
	@Autowired
	@JsonProperty
	private ObjectMapper objectMapper;
	@Autowired
	private AdgroupLogRepository adgroupLogRepository;
	@Autowired
	private CreativeLogRepository creativeLogRepository;
	@Autowired
	private KeywordsLogRepository keywordsLogRepository;
	@Autowired
	private RptKeywordService rptKeywordService;

	@Autowired
	private PlatformService platformService;

	@Autowired
	private OopKeywordService keywordService;

	@Autowired
	private KeywordMapper keywordMapper;

	@SuppressWarnings("unused")
	@RequestMapping(method = RequestMethod.POST, path = "/adgroups")
	@ResponseBody
	public AdgroupDto createAdgroup(@RequestBody AdgroupDto dto) {
		User user = this.userRepository.findOne(dto.getUserID());
		if (user == null) {
			throw new IllegalArgumentException("user_not_foud");
		}
		Assert.isTrue(dto.getDefaultPrice() > 0, "invalid_default_price");

		log.debug("createAdgroup: {}", dto);
		Adgroup adgroup = new Adgroup();
		CreateAdgroupResponse res = this.adgroupClient.createAdgroup(user.getNick(), dto.getCampaignID(),
				dto.getProductID(), dto.getDefaultPrice(), dto.getProductName(), dto.getProductUrl());
		log.debug("start  sync taobao :{},{}", res, res.getError());
		if (res == null) {
			dto.setError(new SimbaProxyBaseDto.Error());
			dto.getError().setCode(-1);
			dto.getError().setMessage("taobao_response_is_null");
			dto.getError().setSubMessage("淘宝返回为空,没有效数据");
			return dto;
		}
		if (res.getError() != null) {
			dto.setError(res.getError());
			return dto;
		}
		if (res.getRes() != null && res.getRes().getAdgroup() != null) {
			AdgroupClient.AdgroupDto tbDto = res.getRes().getAdgroup();
			if (dto.getCreativeImgUrl() != null && dto.getCreativeImgUrl().contains("http") == true
					&& dto.getCreativeImgUrl().contains("https") == true) {
				dto.getCreativeImgUrl().replaceAll("http:", "");
			}
			tbDto.setCreativeName(dto.getCreativeName());
			tbDto.setCreativeImgUrl(dto.getCreativeImgUrl());
			tbDto.setProductName(dto.getProductName());
			log.debug("sync adgroup to taobao: {}", tbDto);
			BeanUtils.copyProperties(dto, adgroup);
			adgroup.setAutoID(tbDto.getAdgroupID());
			BeanUtils.copyProperties(tbDto, adgroup);
			adgroup.setProductName(dto.getProductName());
			adgroup.setLimit(dto.getLimit());
			adgroup.setProductType("");
			adgroup.setDriveType(DriveType.from(dto.getDriveType()));
			adgroup.setOfflineType(OnlineStatus.from(tbDto.getOfflineType()));
			adgroup.setOnlineStatus(OnlineStatus.from(tbDto.getOnlineStatus()));
			adgroup.setStatus(Adgroup.Status.from(dto.getStatus()));
			adgroup.setMobileDiscount(100);
			adgroup.setProductAttributes("");
			adgroup.setMaintainedDate(DateUtils.truncate(new Date(), Calendar.DATE));
			adgroup.setUpdatedTime(new Date());
			adgroup.setAdjustCount(0);
			this.adgroupRepository.save(adgroup);
			dto.setAdgroupID(adgroup.getAutoID());
			/*
			 * 描述：创建推广组日志 adgroups_log 数据库：adgroups_log author:yechen
			 */
			AdgroupVo avo = new AdgroupVo();
			BeanUtils.copyProperties(adgroup, avo);
			AdgroupLog apo = new AdgroupLog();
			BeanUtils.copyProperties(adgroup, apo);
			apo.setAdgroupID(adgroup.getAutoID());
			apo.setCampaignID(adgroup.getProductID());
			apo.setUpdatedTime(new Date());
			if (adgroup.getDriveType() != null && adgroup.getDriveType().getValue() != 0) {
				apo.setAction(AdgroupLog.Action.AUTO_ADD);
			} else {
				apo.setAction(AdgroupLog.Action.MANUAL_ADD);
			}
			try {
				apo.setNote(this.objectMapper.writer().writeValueAsString(avo));
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException: {}", e);
				apo.setNote("");
			}

			this.adgroupLogRepository.save(apo);
			log.debug("sync create adgroup AdgroupLog: {}", apo);

			/**
			 * 增加创意模块 作用：另加一张图片 author：yechen 数据库：creatives
			 */

			if (tbDto.getCreativeName() != null && tbDto.getCreativeImgUrl() != null) {
				CreateCreativeResponse ccRes = this.adgroupClient.createCreatives(user.getNick(), adgroup.getAutoID(),
						tbDto.getCreativeName(), tbDto.getCreativeImgUrl());
				if (ccRes != null && ccRes.getRes() != null && ccRes.getRes().getCreative() != null) {
					AdgroupClient.CreativeDto ctdto = ccRes.getRes().getCreative();
					Creative po = new Creative();
					ctdto.setTitle(tbDto.getCreativeName());
					ctdto.setImage(tbDto.getCreativeImgUrl());
					BeanUtils.copyProperties(ctdto, po);
					BeanUtils.copyProperties(dto, po);
					po.setImage(tbDto.getCreativeImgUrl());
					po.setTitle(tbDto.getCreativeName());
					po.setUserID(user.getUserID());
					po.setUpdatedTime(new Date());
					po.setCreateTime(ctdto.getCreateTime() != null ? ctdto.getCreateTime() : new Date());
					po.setModifiedTime(ctdto.getModifiedTime() != null ? ctdto.getModifiedTime() : new Date());
					po.setAutoID(ctdto.getCreativeID());
					dto.setCreativeName(po.getTitle());
					dto.setCreativeImgUrl(po.getImage());

					log.debug("finish to create creatives as sync2: {} ", po);
				} else {
					if (ccRes != null && ccRes.getError() != null) {
						log.error("fail to add creative as sync: {},{},{},{}",
								"(原因为" + ccRes.getError().getSubMessage() + ")", adgroup, dto, ccRes.getError());
					}
				}
			}
			this.findCreative(user.getNick(), user.getUserID(), dto.getAdgroupID());
		} else {
			if (res != null && res.getError() != null) {
				log.error("fail to create adgroup as sync: {}", "(原因为" + res.getError().getSubMessage() + ")");
				dto.setError(res.getError());
			}
		}

		log.debug("finish to create adgroup as sync : {}", dto);
		return dto;
	}

	public void findCreative(String nick, long userID, long adgroupID) {
		GetCreativeResponse cRes = this.adgroupClient.findCreatives(nick, adgroupID);
		log.debug(">>>>>>>>>>>>><<<<<<<<<<<<<GetCreativeResponse:{}", adgroupID);
		if (cRes != null && cRes.getRes() != null && cRes.getRes().getDataList() != null
				&& cRes.getRes().getDataList().getCreatives() != null) {
			for (AdgroupClient.CreativeDto creativeDto : cRes.getRes().getDataList().getCreatives()) {
				log.debug("fetch creative from taobao: {},>>>{}", creativeDto, cRes);
				Creative po = new Creative();
				BeanUtils.copyProperties(creativeDto, po);
				po.setUserID(userID);
				po.setAutoID(creativeDto.getCreativeID());
				po.setCreateTime(creativeDto.getCreateTime() != null ? creativeDto.getCreateTime() : new Date());
				po.setModifiedTime(creativeDto.getModifiedTime() != null ? creativeDto.getModifiedTime() : new Date());
				po.setUpdatedTime(new Date());
				this.creativeRepository.save(po);
				log.debug("finish to create creatives as sync: {} ", po);

				Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
				CreativeVo creatVo = new CreativeVo();
				BeanUtils.copyProperties(po, creatVo);
				creatVo.setCreativeOldTitle(po.getTitle());
				CreativeLog cpo = new CreativeLog();
				BeanUtils.copyProperties(po, cpo);
				cpo.setAdgroupID(po.getAdgroupID());
				cpo.setCreativeID(po.getAutoID());
				cpo.setUpdatedTime(new Date());
				if (adgroup.getDriveType() != null && adgroup.getDriveType().getValue() != 0) {
					cpo.setAction(CreativeLog.Action.AUTO_ADD);
				} else {
					cpo.setAction(CreativeLog.Action.MANUAL_ADD);
				}
				try {
					cpo.setNote(this.objectMapper.writer().writeValueAsString(creatVo));
				} catch (JsonProcessingException e) {
					log.error("JsonProcessingException: {}", e);
					cpo.setNote("");
				}
				this.creativeLogRepository.save(cpo);
				log.debug("sync create creative CreativeLog: {}", cpo);

			}
		}
	}

	@RequestMapping(method = RequestMethod.PUT, path = "/adgroups/{adgroup_id}/@status")
	@ResponseBody
	public AdgroupDto updateAdgroupStatus(@PathVariable("adgroup_id") long adgroupID, @RequestBody AdgroupDto dto) {
		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "adgroup_not_foud");

		log.debug("updateAdgroupStatus: {}, {}", adgroupID, dto);
		adgroup.setStatus(Adgroup.Status.from(dto.getStatus()));
		adgroup.setUpdatedTime(new Date());
		this.adgroupRepository.save(adgroup);

		BeanUtils.copyProperties(adgroup, dto);
		return dto;
	}

	@RequestMapping(method = RequestMethod.PUT, path = "/adgroups/{adgroup_id}")
	@ResponseBody
	public AdgroupDto updateAdgroup(@PathVariable("adgroup_id") long adgroupID, @RequestBody AdgroupDto dto) {
		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "adgroup_not_foud");

		log.debug("updateAdgroup: {}, {}", adgroupID, dto);
		if (dto.getStatus() > -1) {
			adgroup.setStatus(Adgroup.Status.from(dto.getStatus()));
		}
		if (dto.getMaintainedDate() != null) {
			adgroup.setMaintainedDate(dto.getMaintainedDate());
		}
		if (dto.getLimit() != 0 && dto.getLimit() != adgroup.getLimit()) {
			adgroup.setLimit(dto.getLimit());
			this.adgroupRepository.save(adgroup);

			AdgroupVo avo = new AdgroupVo();
			BeanUtils.copyProperties(adgroup, avo);
			avo.setOldLimit(adgroup.getLimit());
			avo.setNewLimit(dto.getLimit());
			AdgroupLog apo = new AdgroupLog();
			BeanUtils.copyProperties(adgroup, apo);
			apo.setAdgroupID(adgroup.getAutoID());
			apo.setCampaignID(adgroup.getProductID());
			apo.setUpdatedTime(new Date());
			apo.setAction(AdgroupLog.Action.MANUAL_UPDATE_MAXPRICE);
			try {
				apo.setNote(this.objectMapper.writer().writeValueAsString(avo));
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException: {}", e);
				apo.setNote("");
			}
		}
		if (dto.getDriveType() >= 0 && dto.getDriveType() != adgroup.getDriveType().getValue()) {
			adgroup.setDriveType(DriveType.from(dto.getDriveType()));
			adgroup.setUpdatedTime(new Date());
			this.adgroupRepository.save(adgroup);

			AdgroupLog po = new AdgroupLog();
			BeanUtils.copyProperties(adgroup, po);
			po.setAdgroupID(adgroup.getAutoID());
			po.setCampaignID(adgroup.getCampaignID());
			po.setUpdatedTime(new Date());
			po.setAction(AdgroupLog.Action.SWITCH_DRIVE_TYPE);
			po.setNewIntval(adgroup.getDriveType().getValue());
			po.setNote("");

			this.adgroupLogRepository.save(po);
			log.debug("sync update adgroup AdgroupLog: {}", po);
		}
		if (dto.getAdjustCount() > 0 && dto.getAdjustCount() != adgroup.getAdjustCount()) {
			adgroup.setAdjustCount(dto.getAdjustCount());
		}
		if (dto.getLineStatus() != null && !(dto.getLineStatus().equals(adgroup.getOnlineStatus().getValue()))) {
			adgroup.setOnlineStatus(OnlineStatus.from(dto.getLineStatus()));
			adgroup.setUpdatedTime(new Date());
			this.adgroupRepository.save(adgroup);

			AdgroupVo avo = new AdgroupVo();
			BeanUtils.copyProperties(adgroup, avo);
			AdgroupLog po = new AdgroupLog();
			BeanUtils.copyProperties(adgroup, po);
			po.setAdgroupID(adgroup.getAutoID());
			po.setCampaignID(adgroup.getCampaignID());
			po.setUpdatedTime(new Date());
			if (adgroup.getOnlineStatus().getValue().equals("online")) {
				po.setAction(AdgroupLog.Action.MANUAL_PAUSE);
			} else {
				po.setAction(AdgroupLog.Action.MANUAL_OPEN);
			}
			po.setNote("");

			this.adgroupLogRepository.save(po);
			log.debug("sync update adgroup AdgroupLog: {}", po);

		}
		adgroup.setUpdatedTime(new Date());
		this.adgroupRepository.save(adgroup);
		BeanUtils.copyProperties(adgroup, dto);
		dto.setLineStatus(adgroup.getOnlineStatus().getValue());
		dto.setDriveType(adgroup.getDriveType().getValue());

		return dto;

	}

	/**
	 * 删除某个推广宝贝
	 * 
	 * @param adgroupID
	 * @return
	 */
	@RequestMapping(method = RequestMethod.DELETE, path = "/adgroups/{adgroup_id}")
	@ResponseBody
	public AdgroupDto delAdgroup(@PathVariable("adgroup_id") long adgroupID) {
		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "adgroup_not_exist");
		AdgroupDto dto = new AdgroupDto();
		BeanUtils.copyProperties(adgroup, dto);
		dto.setAdgroupID(adgroup.getAutoID());
		this.adgroupRepository.delete(adgroup);

		AdgroupLog adgroupLog = new AdgroupLog();
		adgroupLog.setAdgroupID(dto.getAdgroupID());
		adgroupLog.setAction(AdgroupLog.Action.MANUAL_DEL);
		adgroupLog.setCampaignID(dto.getCampaignID());
		adgroupLog.setUpdatedTime(new Date());

		AdgroupVo avo = new AdgroupVo(); // 存入log表的note字段的json值的类
		BeanUtils.copyProperties(dto, avo);
		avo.setAutoID(dto.getAdgroupID());
		try {
			adgroupLog.setNote(this.objectMapper.writer().writeValueAsString(avo));
		} catch (JsonProcessingException e) {
			log.error("JsonProcessingException: {}", e);
			adgroupLog.setNote("");
		}
		this.adgroupLogRepository.save(adgroupLog);
		log.debug("sync del adgroup to AdgroupLog: {}", adgroupLog);

		return dto;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@RequestMapping(method = RequestMethod.GET, path = "/adgroups/{adgroup_id}/actions")
	@ResponseBody
	public Page<LogDto<LogDto.LogNoteable>> findAdgroupLog(@PathVariable("adgroup_id") long adgroupID,
			@RequestParam(name = "type", defaultValue = "adgroup") String type,
			@RequestParam(name = "page_num", defaultValue = "0") int page,
			@RequestParam(name = "page_size", defaultValue = "50") int size) {
		PageRequest pr = new PageRequest(page, size);

		Page<LogDto<LogDto.LogNoteable>> dtos = null;
		Date today = DateUtils.truncate(new Date(), Calendar.DATE);
		SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");

		if ("adgroup".equals(type)) {
			Page<AdgroupLog> logs = this.adgroupLogRepository.findByAdgroupIDAndUpdatedTimeAfterOrderByUpdatedTimeDesc(
					adgroupID, DateUtils.addDays(today, -14), pr);
			List<LogDto<LogDto.LogNoteable>> list = new ArrayList<LogDto<LogDto.LogNoteable>>();
			for (AdgroupLog alog : logs) {
				LogDto dto = new LogDto<AdgroupVo>();
				BeanUtils.copyProperties(alog, dto);
				dto.setAction(alog.getAction().toDisplay());
				dto.setUpdatedTime(sdf.format(alog.getUpdatedTime()));
				if (!(alog.getNote().equals(""))) {
					try {
						dto.setNote(this.objectMapper.readerFor(AdgroupVo.class).readValue(alog.getNote()));
					} catch (IOException e) {
						log.error("IOException:{}", e);
					}
				}
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, logs.getTotalElements());
		} else if ("creative".equals(type)) {
			Page<CreativeLog> logs = this.creativeLogRepository
					.findByAdgroupIDAndUpdatedTimeAfterOrderByUpdatedTimeDesc(adgroupID, DateUtils.addDays(today, -14),
							pr);
			List<LogDto<LogDto.LogNoteable>> list = new ArrayList<LogDto<LogDto.LogNoteable>>();
			for (CreativeLog clog : logs) {
				LogDto dto = new LogDto<CreativeVo>();
				BeanUtils.copyProperties(clog, dto);
				dto.setAction(clog.getAction().toDisplay());
				dto.setUpdatedTime(sdf.format(clog.getUpdatedTime()));
				if (!(clog.getNote().equals(""))) {
					try {
						dto.setNote(this.objectMapper.readerFor(CreativeVo.class).readValue(clog.getNote()));
					} catch (IOException e) {
						log.error("IOException:{}", e);
					}
				}
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, logs.getTotalElements());
		} else {
			Page<KeywordsLog> logs = this.keywordsLogRepository
					.findByAdgroupIDAndUpdatedTimeAfterOrderByUpdatedTimeDesc(adgroupID, DateUtils.addDays(today, -14),
							pr);
			List<LogDto<LogDto.LogNoteable>> list = new ArrayList<LogDto<LogDto.LogNoteable>>();
			for (KeywordsLog klog : logs) {
				LogDto dto = new LogDto<KeywordsVo>();
				BeanUtils.copyProperties(klog, dto);
				dto.setAction(klog.getAction().toDisplay());
				dto.setKeyword(klog.getKeyword());
				dto.setUpdatedTime(sdf.format(klog.getUpdatedTime()));
				dto.setNewValue(klog.getNewIntVal());
				if (!(klog.getNote().equals(""))) {
					try {
						DisplayKeywordVo dv = new DisplayKeywordVo();
						ConvertKeywordNewVo cnv = new ConvertKeywordNewVo();
						DisplayKeywordNewVo dnv = new DisplayKeywordNewVo();
						DisplayKeywordOldVo dov = new DisplayKeywordOldVo();
						if (klog.getNote().contains("\"new\":\"")) {
							cnv = this.objectMapper.readerFor(ConvertKeywordNewVo.class).readValue(klog.getNote());
							dv.setOldNote(platformService.unserializeKeyword(cnv.getOldNoteStr()));
							dv.setNewNote(platformService.unserializeKeyword(cnv.getNewNoteStr()));
						} else if (klog.getNote().contains("\"old\":\"")) {
							dnv = this.objectMapper.readerFor(DisplayKeywordNewVo.class).readValue(klog.getNote());
							dv.setNewNote(dnv.getNewNote());
							dv.setOldNote(platformService.unserializeKeyword(dnv.getOldNoteStr()));
						} else {
							dov = this.objectMapper.readerFor(DisplayKeywordOldVo.class).readValue(klog.getNote());
							dv.setNewNote(dov.getNewNote());
							dv.setOldNote(dov.getOldNote());
						}

						Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
						if (dv.getOldNote() != null && dv.getOldNote().getMaxMobilePrice() == null
								&& dv.getOldNote().getMaxPrice() != null) {
							dv.getOldNote().setMaxMobilePrice(
									(dv.getOldNote().getMaxPrice() * adgroup.getMobileDiscount()) / 100);
						}
						if (dv.getNewNote() != null && dv.getNewNote().getMaxMobilePrice() == null
								&& dv.getNewNote().getMaxPrice() != null) {
							dv.getNewNote().setMaxMobilePrice(
									(dv.getNewNote().getMaxPrice() * adgroup.getMobileDiscount()) / 100);

						}
						dto.setNote(dv);
					} catch (IOException e) {
						log.error("IOException:{}", e);
					}
				}
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, logs.getTotalElements());
		}
		return dtos;
	}

	@RequestMapping(method = RequestMethod.PUT, path = "/creatives/{creative_id}")
	@ResponseBody
	public AdgroupDto updateCreative(@PathVariable("creative_id") long creativeID, @RequestBody AdgroupDto dto) {
		Creative creative = this.creativeRepository.findOne(creativeID);
		Assert.notNull("creative_not_found");

		log.debug("update creative: {},{}", creativeID, dto);
		CreativeVo creatVo = new CreativeVo();
		if (dto.getCreativeName() != null && !(dto.getCreativeName().equals(creative.getTitle()))) {
			creatVo.setCreativeOldTitle(creative.getTitle());
			creatVo.setCreativeNewTitle(dto.getCreativeName());
			creative.setTitle(dto.getCreativeName());
		}
		if (dto.getCreativeImgUrl() != null && !(dto.getCreativeImgUrl().equals(creative.getImage()))) {
			creatVo.setOldImage(creative.getImage());
			creatVo.setNewImage(dto.getCreativeImgUrl());
			creative.setImage(dto.getCreativeImgUrl());
		}
		creative.setUpdatedTime(new Date());
		this.creativeRepository.save(creative);
		BeanUtils.copyProperties(creative, creatVo);

		CreativeLog cpo = new CreativeLog();
		cpo.setAdgroupID(creative.getAdgroupID());
		cpo.setCreativeID(creative.getAutoID());
		cpo.setUpdatedTime(new Date());
		cpo.setAction(CreativeLog.Action.MANUAL_UPDATE);
		try {
			cpo.setNote(this.objectMapper.writer().writeValueAsString(creatVo));
		} catch (JsonProcessingException e) {
			log.error("JsonProcessingException: {}", e);
			cpo.setNote("");
		}

		this.creativeLogRepository.save(cpo);
		log.debug("sync create creative CreativeLog: {}", cpo);

		return dto;
	}

	@RequestMapping("/adgroups/{adgroup_id}/reports/trend")
	public @ResponseBody Object reportsTrend(@PathVariable("adgroup_id") Long adgroupId,
			@RequestParam(defaultValue = "7") Integer days, @RequestParam(required = false) Integer device,
			@RequestParam(required = false) String startDate, @RequestParam(required = false) String endDate) {
		log.info("reportsTrend RequestParam adgroupId:{} days:{} device:{} startDate:{} endDate:{}", adgroupId, days,
				device, startDate, endDate);
		RptKeywordParam param = new RptKeywordParam();
		param.setUserId(adgroupRepository.findOne(adgroupId).getUserID());
		param.setAdgroupId(adgroupId);
		param.setDay(days);
		if (device != null) {
			param.setSource(device.byteValue());
		}
		param.setStartDate(startDate);
		param.setEndDate(endDate);
		return rptKeywordService.getReportsTrendByDate(param);
	}

	@RequestMapping("/adgroups/{adgroup_id}/keywordStates")
	public @ResponseBody Object keywordStates(@PathVariable("adgroup_id") Long adgroupId,
			@RequestParam(defaultValue = "7") Integer days, @RequestParam(required = false) Integer device,
			@RequestParam(required = false) String startDate, @RequestParam(required = false) String endDate) {
		log.info("keywordStates RequestParam adgroupId:{} days:{} device:{} startDate:{} endDate:{}", adgroupId, days,
				device, startDate, endDate);
		RptKeywordParam param = new RptKeywordParam();
		param.setUserId(adgroupRepository.findOne(adgroupId).getUserID());
		param.setAdgroupId(adgroupId);
		param.setDay(days);
		if (device != null) {
			param.setSource(device.byteValue());
		}
		param.setStartDate(startDate);
		param.setEndDate(endDate);
		return rptKeywordService.getReportsTrend(param);
	}

	@Data
	@JsonInclude(Include.NON_NULL)
	public static class AdgroupDto {

		@JsonProperty("adgroup_id")
		private long adgroupID;

		@JsonProperty("user_id")
		private long userID;
		private String nick;
		@JsonProperty("campaign_id")
		private long campaignID;
		@JsonProperty("product_id")
		private long productID;
		@JsonProperty("title")
		private String productName;
		@JsonProperty("img_url")
		private String productUrl;
		@JsonProperty("drive_type")
		private int driveType = -1;
		@JsonProperty("default_price")
		private int defaultPrice;

		/**
		 * below fields are only for update
		 */
		@JsonProperty("line_status")
		private String lineStatus;
		private int status;

		@JsonProperty("maintainDate")
		@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
		private Date maintainedDate;

		@JsonProperty("creative_title")
		private String creativeName;
		@JsonProperty("creative_img_url")
		private String creativeImgUrl;
		@JsonProperty("adjust_count")
		private int adjustCount;

		private int limit;

		private SimbaProxyBaseDto.Error error;
	}

	@RequestMapping(method = RequestMethod.PUT, path = "/adgroups/{adgroup_id}/actions")
	@ResponseBody
	public DeferredResult<AdgroupResponse> updateAdgroupWithKeyword(@PathVariable("adgroup_id") long adgroupID) {
		final DeferredResult<AdgroupResponse> result = new DeferredResult<AdgroupResponse>();
		final AdgroupResponse res = new AdgroupResponse();
		result.onTimeout(new Runnable() {
			@Override
			public void run() {
				res.setStatus(false);
				res.setMessage("timeout");
				result.setResult(res);
				log.error("timeout updateAdgroupWithKeyword {}", adgroupID);
			}
		});

		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		if (adgroup == null) {
			throw new IllegalArgumentException("adgroup_not_foud");
		}
		if (adgroup.getLimit() == 0) {
			throw new IllegalArgumentException("no_limit");
		}
		User user = this.userRepository.findOne(adgroup.getUserID());
		if (user == null) {
			throw new IllegalArgumentException("user_not_foud");
		}

		KeywordExample ex = new KeywordExample();
		ex.setUserId(adgroup.getUserID());
		ex.createCriteria().andAdgroupIdEqualTo(adgroupID);
		List<Keyword> keywords = this.keywordMapper.selectByExample(ex);

		List<PricingKeyword> pricingKeywords = new ArrayList<PricingKeyword>();
		for (Keyword key : keywords) {
			PricingKeyword pk = new PricingKeyword();
			pk.setKeywordID(key.getKeywordId());
			pk.setMatchScope(key.getMatchscope());
			pk.setIsDefaultPrice(key.getIsDefaultPrice() ? 1 : 0);
			pk.setMobileIsDefaultPrice(key.getMobileIsDefaultPrice());
			pk.setMaxPrice(key.getMaxPrice());
			pk.setMaxMobilePrice(key.getMaxMobilePrice());
			boolean needUpdate = false;
			if (adgroup.getLimit() < key.getMaxMobilePrice()) {
				pk.setMaxMobilePrice(adgroup.getLimit());
				needUpdate = true;
			}
			if (adgroup.getLimit() < key.getMaxPrice()) {
				pk.setMaxPrice(adgroup.getLimit());
				needUpdate = true;
			}
			if (needUpdate) {
				pricingKeywords.add(pk);
			}
		}

		if (pricingKeywords.size() > 0) {
			this.keywordService.price(user, pricingKeywords, new OopKeywordService.Callback() {
				@Override
				public void call(List<Keyword> keywords) {
					log.debug("finish setprice:{}", res);
					res.setStatus(true);
					result.setResult(res);
				}
			}, true, false);
		} else {
			res.setStatus(false);
			res.setMessage("no_keyword_to_pricing");
			result.setResult(res);
		}

		return result;
	}

	/**
	 * 获取关键词相关信息
	 * 
	 * @param adgroupID
	 * @param type
	 * @param maxPrice
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET, path = "/adgroups/{adgroup_id}/keywords")
	@ResponseBody
	public ListResponse<Keyword> findKeywords(@PathVariable("adgroup_id") long adgroupID,
			@RequestParam(name = "filters", defaultValue = "max_price") List<String> filters,
			@RequestParam(name = "max_price", required = false, defaultValue = "0") int maxPrice) {

		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		KeywordExample ex = new KeywordExample();
		ex.setUserId(adgroup.getUserID());
		ex.createCriteria().andAdgroupIdEqualTo(adgroupID);
		List<Keyword> keywords = this.keywordMapper.selectByExample(ex);

		ListResponse<Keyword> dto = new ListResponse<Keyword>();

		dto.setDatas(new ArrayList<Keyword>());
		for (Keyword key : keywords) {
			boolean canAdd = true;
			boolean needUpdate = false;
			if (filters != null) {
				if (filters.indexOf("max_price") > -1) {
					canAdd = canAdd && (maxPrice < key.getMaxMobilePrice() || maxPrice < key.getMaxPrice());
					needUpdate = true;
				}
			}
			if (canAdd && needUpdate) {
				dto.getDatas().add(key);
			}
		}
		dto.setTotal(dto.getDatas().size());
		dto.setStatus(true);

		return dto;
	}

	@Data
	public static class AdgroupResponse {
		private boolean status;
		private String message;
	}
}